package lang;

import lang.vo.MyObject;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

/**
 * @Author tuyou_cd
 * @Date 2020/7/22 15:17
 */
public class ThreadLocalTest {

    /**
     * 简单使用测试
     */
    @Test
    public void test() {

        ThreadLocal<MyObject> threadLocal = new ThreadLocal<>();
        threadLocal.set(new MyObject("1"));
        System.out.println(threadLocal.get());

        threadLocal.remove(); //调用remove，好让gc回收value
        System.out.println(threadLocal.get());
    }

    /**
     * 测试内存泄漏
     * 根源是没有调用ThreadLocal.remove方法
     */
    @Test
    public void memoryLeak() throws InterruptedException {

        ThreadLocal<MyObject> threadLocal = new ThreadLocal() {
            @Override
            protected void finalize() throws Throwable {
                System.out.println("ThreadLocal被gc");
            }
        };
        threadLocal.set(new MyObject("1"));
        threadLocal.set(new MyObject("2")); //如果不调用remove，最后一个set的value不会被回收
//        threadLocal.remove(); //不调用会内存泄漏，MyObject被ThreadLocalMap.Entry的value一直强引用着
        threadLocal = null;
        System.gc(); //threadLocal和new MyObject("1")被gc回收，new MyObject("2")还没被回收
        TimeUnit.SECONDS.sleep(1);

        //通过其他ThreadLocal的get/set/remove方法触发清除ThreadLocalMap.Entry中new MyObject("2")的引用
        for (int i = 0; i < 11; i++) {
            ThreadLocal otherLocal = new ThreadLocal();
            otherLocal.set(i);
        }
        System.gc(); //new MyObject("2")终于被这次gc回收
        TimeUnit.SECONDS.sleep(1);
    }
}
